package simple.word;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

import edu.smu.tspell.wordnet.SynsetType;
import edu.smu.tspell.wordnet.WordNetDatabase;
import edu.smu.tspell.wordnet.impl.file.Morphology;

public class Main {

	static Options makeOptions() {
		Options options = new Options();
		
		options.addOption("d", true, "Dictionary location");
		options.addOption("l", true, "List of the candidate words");
		
		return options;
	}

	static void usage(Options options)
	{
		HelpFormatter formatter = new HelpFormatter();
		formatter.printHelp("java -cp <classpath> " + Main.class.getName(), options);
	}
	
	static HashMap<String, ExtraWordMapping> extraMapping = new HashMap<>();
	
	static {
		new ExtraWordMapping("his", "one's").putToMap(extraMapping);
		new ExtraWordMapping("her", "one's").putToMap(extraMapping);
		new ExtraWordMapping("its", "one's").putToMap(extraMapping);
		new ExtraWordMapping("their", "one's").putToMap(extraMapping);
	}

	public static void main(String[] args) throws Exception {
		Options options = makeOptions();
		
		CommandLineParser parser = new PosixParser();
		File inputFile = null;
		
		
		try {
			CommandLine line = parser.parse(options, args);
			
			String value = line.getOptionValue('d');
			if(value == null) {
				System.err.println("Missing Dictionary location");
				usage(options);
				System.exit(1);
			}
			
			System.setProperty("wordnet.database.dir", value);
			
			value = line.getOptionValue('l');
			if(value == null) {
				System.err.println("Missing input file");
				usage(options);
				System.exit(1);
			}
			
			inputFile = new File(value);
			if(!inputFile.exists()) {
				System.err.println("Missing file " + inputFile.getAbsolutePath());
				System.exit(1);
			}
			
			
		} catch (ParseException ex) {
			System.err.println(ex.getMessage());
			usage(options);
			System.exit(1);
		}
		
		WordNetDatabase.getFileInstance();
		
		Morphology id = Morphology.getInstance();

		String inputLine;
		try (FileReader fr = new FileReader(inputFile);
				BufferedReader br = new BufferedReader(fr);) {
			while ((inputLine = br.readLine()) != null) {
				inputLine = inputLine.trim();
				inputLine = inputLine.toLowerCase();

				String[] sep = inputLine.split(" ");

				if (sep.length == 1) {
					System.out.println(inputLine);

					List<String> candidates = lookForCandidates(id, inputLine);
					for (String c : candidates)
						System.out.println(c);
				} else {
					handleCombinations(id, sep);
				}
			}
		}
		
	}

	static void handleCombinations(Morphology id, String[] sep) {
		ArrayList<List<String>> sepCandidates = new ArrayList<>();
		
		for(int k = 0; k<sep.length; ++k) {
			String word = sep[k];
			List<String> cs = lookForCandidates(id, word);
			ArrayList<String> csList = new ArrayList<>(cs);
			csList.add(0, word);
			
			if(extraMapping.containsKey(word))
				csList.addAll(extraMapping.get(word).getCandidates());
			
			sepCandidates.add(csList);
				
		}
		
		int[] pathIds = new int[sep.length];
		for(int k=0; k<pathIds.length; ++k)
			pathIds[k] = 0;
		
		Stack<Integer> stack = new Stack<>();
		for (int k = 0; k < sep.length; ++k) {
			stack.add(0);
		}
		do {
			for(int k=0; k<stack.size(); ++k) {
				System.out.print(sepCandidates.get(k).get(stack.get(k)) + " ");
			}
			System.out.println();
			
			while(!stack.isEmpty()) {
				int value = stack.pop();
				if(value < sepCandidates.get(stack.size()).size() - 1) {
					stack.add(value + 1);
					break;
				}
			}
			if(stack.isEmpty())
				break;

			for(int k=stack.size(); k < sep.length; ++k) {
				stack.add(0);
			}
		} while(true);
	}
	
	static List<String> lookForCandidates(Morphology id, String inputLine) {
		List<String> candidates = new ArrayList<>();
		
		//noun
		String [] baseForms = id.getBaseFormCandidates(inputLine, SynsetType.NOUN);
		if(baseForms.length > 0)
		{
			for(String x : baseForms)
			{
				//System.out.println(x);
				candidates.add(x);
			}
		}
		
		//verb
		baseForms = id.getBaseFormCandidates(inputLine, SynsetType.VERB);
		if(baseForms.length > 0)
		{
			for(String x : baseForms)
			{
				//System.out.println(x);
				candidates.add(x);
			}
		}
		
		//adjective
		baseForms = id.getBaseFormCandidates(inputLine, SynsetType.ADJECTIVE);
		if(baseForms.length > 0)
		{
			for(String x : baseForms)
			{
				//System.out.println(x);
				candidates.add(x);
			}
		}

		baseForms = id.getBaseFormCandidates(inputLine, SynsetType.ADVERB);
			if(baseForms.length > 0)
			{
				for(String x : baseForms)
				{
					//System.out.println(x);
					candidates.add(x);
				}
			}
			
			return candidates;
	}

}
